Чтобы попрактиковаться в использовании массивов, мы создадим нашу собственную версию макроса, которую мы использовали для демонстрации преимущества массивов в скорости, шаг за шагом ...
Далее начальная точка этого упражнения (вы увидите, что набор данных был уменьшен до 1000 строк):
Здесь вы можете скачать Excel файл с примером: arrays_exercise.xls
Цель упражнения: процедура должна обрабатывать данные в наборе данных с помощью цикла и посчитать количество ответов "ДА" или "НЕТ" для каждого года и для каждого номера клиента (или "ДА" или "НЕТ", в зависимости от выбора пользователя) и ввести это количество в указанную ячейку рабочего листа.
Завершите следующий макрос, чтобы сохранить данные из рабочего листа «DS» в массив:
Sub actualize () Dim last_row As Integer 'Последняя строка набора данных '... 'Сохранение набора данных в динамическом массиве Dim array_db() '... End Sub
Вот один из примеров решения:
Sub actualize () Dim last_row As Integer 'Последняя строка базы данных last_row = Sheets("DS").Range("A1").End(xlDown).Row 'Сохранение набора данных в динамическом массиве Dim array_db() ReDim array_db(last_row - 2, 2) For row_number = 2 To last_row array_db(row_number - 2, 0) = Sheets("DS").Range("A" & row_number) array_db(row_number - 2, 1) = Sheets("DS").Range("B" & row_number) array_db(row_number - 2, 2) = Sheets("DS").Range("C" & row_number) Next End Sub
Это в основном повторяет то, что мы делали на предыдущем уроке ...
Но сейчас нам нужно изменить наш макрос добавлением следующих действий:
Определить выбор пользователя ("ДА" или "НЕТ");
Посчитать количество ответов "ДА" или "НЕТ" в наборе данных, для того чтобы определить размер массива (Redim);
Сохраняем только те строки из набора данных, которые содержат ответы "ДА" или "НЕТ" в массиве (это означает, что не нужно хранить данные с третьего столбца).
Вот один из примеров решения:
Sub actualize() Dim last_row As Integer, search_value As String, insert_row As Integer, value_yes_no As String, rows_number As Integer 'Последняя строка базы данных last_row = Sheets("DS").Range("A1").End(xlDown).Row 'Поиск значения (YES или NO) If Sheets("RES").OptionButton_yes.Value = True Then search_value = "YES" Else search_value = "NO" End If 'Количество ответов YES или NO rows_number = WorksheetFunction.CountIf(Sheets("DS").Range("C2:C" & last_row), search_value) 'Сохранение набора данных в массив Dim array_db() ReDim array_db(rows_number - 1, 1) insert_row = 0 For row_number = 2 To last_row value_yes_no = Sheets("DS").Range("C" & row_number) If value_yes_no = search_value Then array_db(insert_row, 0) = Sheets("DS").Range("A" & row_number) array_db(insert_row, 1) = Sheets("DS").Range("B" & row_number) insert_row = insert_row + 1 End If Next End Sub
Поиск выбранного пользователем определяется в начале процедуры следующим кодом:
'Поиск значения (YES или NO) If Sheets("RES").OptionButton_yes.Value = True Then search_value = "YES" Else search_value = "NO" End If
Мы используем функцию CountIF , чтобы определить количество ответов "ДА" или "НЕТ":
'Количество ответов YES или NO rows_number = WorksheetFunction.CountIf(Sheets("DS").Range("C2:C" & last_row), search_value)
Размер массива был изменен, чтобы соответствовать количеству ответов "ДА" или "НЕТ" и уменьшить до двух столбцов:
ReDim array_db(rows_number - 1, 1)
Теперь эти данные будут сохранены в массиве, когда его третий столбец соответствует выбору пользователя:
'Установка номера в массив insert_row = 0 'Обработка набора данных For row_number = 2 To last_row 'Значение столбца C (YES или NO) value_yes_no = Sheets("DS").Range("C" & row_number) 'Если значение соответствует выбору пользователя, строка сохраняется в массиве If value_yes_no = search_value Then 'Сохранение значение в столбец A array_db (insert_row, 0) = Sheets("DS").Range("A" & row_number) 'Сохранение значение в столбец B array_db (insert_row, 1) = Sheets("DS").Range("B" & row_number) 'Одна строка была сохранена => номер вставки в массиве увеличивается на 1 insert_row = insert_row + 1 End If Next
Наш массив содержит только те данные, которые нас интересуют.
Все, что нам осталось сделать, это:
Обработать каждый элемент таблицы на рабочем листе "RES", используя 2 цикла (такая же идея, как в упражнении с шахматной доской);
Вставить общее количество вхождений на этом листе для каждого года в разрезе каждого номера клиента для каждой ячейки.
Вот один из примеров решения:
'Количество ответов "YES"/"NO" For no_years = 2011 To 2026 For no_client = 1 To 30 counter = 0 For i = 0 To UBound(array_db) If Year(array_db(i, 0)) = no_years And array_db(i, 1) = no_client Then counter = counter + 1 End If Next Cells(no_years - 2009, no_client + 1) = counter Next Next
Решение задачи с комментариями, которые объясняют это в деталях:
'Цикл для каждой строки For no_years = 2011 To 2026 'Цикл для каждого столбца For no_client = 1 To 30 'Сброс счетчика counter = 0 'Обработка массива For i = 0 To UBound (array_db) 'Проверка, что строка в таблице соответствует году и номеру клиента If Year (array_db (i, 0)) = no_years And array_db (i, 1) = no_client Then 'Если год и номер клиента отвечает, счетчик увеличивается на 1 counter = counter + 1 End If Next 'После обработки массива, итог вводится в соответствующую ячейку Cells(no_years - 2009, no_client + 1) = counter Next Next
И наконец, код всего нашего макроса:
Sub actualize() Dim last_row As Integer, search_value As String, insert_row As Integer, value_yes_no As String, rows_number As Integer, counter As Integer 'Удаление содержания Range("B2:AE17").ClearContents 'Последняя строка в наборе данных last_row = Sheets("DS").Range("A1").End(xlDown).Row 'Поиск значения (YES или NO) If Sheets("RES").OptionButton_yes.Value = True Then search_value = "YES" Else search_value = "NO" End If 'Количество ответов YES или NO rows_number = WorksheetFunction.CountIf(Sheets("DS").Range("C2:C" & last_row), search_value) 'Сохранение значений в массив Dim array_db() ReDim array_db(rows_number - 1, 1) insert_row = 0 For row_number = 2 To last_row value_yes_no = Sheets("DS").Range("C" & row_number) If value_yes_no = search_value Then array_db(insert_row, 0) = Sheets("DS").Range("A" & row_number) array_db(insert_row, 1) = Sheets("DS").Range("B" & row_number) insert_row = insert_row + 1 End If Next 'Подсчет ответов YES или NO For no_years = 2011 To 2026 For no_client = 1 To 30 counter = 0 For i = 0 To UBound(array_db) If Year(array_db(i, 0)) = no_years And array_db(i, 1) = no_client Then counter = counter + 1 End If Next Cells(no_years - 2009, no_client + 1) = counter Next Next End Sub
Здесь вы можете скачать Excel файл с примером: arrays_exercise_completed.xls